# -*- coding: utf-8 -*-

import ast

from ir.ir_node import *
from ir.ir_type import ITypeStr
from ir.ir_helper import Helper

from .convert_exp import convert_list
from .convert_method import convert_body
from .helper_utils import create_class_helper


def convert_node_tasks(node_type: ITypeNode, helper: Helper):
    # Loop for all the function definition.
    for ast_task in node_type.ir_methods:
        # Ignore the initial method.
        if ast_task.name == 'initialize':
            continue
        # All the other method should be a task.
        task_body = convert_body(ast_task.body, helper, node_type)
        # Construct the task name.
        # Create task class.
        node_type.task_body.append(ITask(name=ast_task.name, body=task_body))


def convert_node_struct(ast_node: ast.ClassDef, helper: Helper):
    # Create this definition.
    this = ITypeNode(ast_node.name)
    # Create node helper.
    this.helper = create_class_helper('Node', helper.chelper)
    # Split the node code lines.
    for ast_line in ast_node.body:
        # Check the body type, only focus on the following types:
        # Assign: it is the task list.
        # FunctionDef: it is a task implementation.
        if isinstance(ast_line, ast.FunctionDef):
            this.ir_methods.append(ast_line)
        elif isinstance(ast_line, ast.Assign):
            # Parse the task list.
            if len(ast_line.targets) != 1 or not isinstance(ast_line.targets[0], ast.Name):
                continue
            # Parse the assign target name.
            target_name = ast_line.targets[0].id
            if target_name != 'tasks':
                continue
            # Parse the value data.
            ir_tasks = convert_list(ast_line.value, helper, None)
            if ir_tasks.type.managed_type != ITypeStr:
                if ir_tasks.type.managed_type is not None:
                    raise Exception('Task list must be a string list which records the name of the task method.')
                else:
                    # It is an empty list, force set the type to be string.
                    ir_tasks.type.managed_type = ITypeStr
            this.tasks = ir_tasks
    # Convert the initialize() method.
    initial_func = None
    for ast_funcdef in this.ir_methods:
        if ast_funcdef.name == 'initialize':
            initial_func = ast_funcdef
            break
    # If fail to find the init function, raise the Exception.
    if initial_func is None:
        raise Exception('No initialize method find for Node {}.'.format(this.name))
    # Convert the method.
    this.initial = convert_body(initial_func.body, helper, this)
    # Now we have the node definition, give back the node type and its helper.
    return [this], [this.helper]
